﻿#include "fdset.h"
#ifdef PLATFORM_LINUX
#include <stdlib.h>
#include <string.h>
#endif

SocketLib::SocketSet::SocketSet()
{
    FD_ZERO(&_readSet);
    FD_ZERO(&_writeSet);
    FD_ZERO(&_errorSet);

    FD_ZERO(&m_readSetResult);
    FD_ZERO(&m_writeSetResult);
    FD_ZERO(&m_errorSet);

#ifdef PLATFORM_LINUX
    m_maxSock = SOCKET_ERROR;
    m_socks = new DVector<bool>(10000);
#endif
}

SocketLib::SocketSet::~SocketSet()
{
#ifdef PLATFORM_LINUX
    m_maxSock = SOCKET_ERROR;
    if(NULL != m_socks)
    {
        delete m_socks;
        m_socks = NULL;
    }
#endif
}

void SocketLib::SocketSet::addSock(sock aSock, int aType)
{
    if(aType & ReadActive)
    {
        FD_SET(aSock, &_readSet);
    }

    if(aType & WriteActive)
    {
        FD_SET(aSock, &_writeSet);
    }

    if(aType & ErrorActive)
    {
        FD_SET(aSock, &_errorSet);
    }
}

void SocketLib::SocketSet::delSock(sock aSock, int aType)
{
    if(aType & ReadActive)
    {
        FD_CLR(aSock, &_readSet);
    }

    if(aType & WriteActive)
    {
        FD_CLR(aSock, &_writeSet);
    }

    if(aType & ErrorActive)
    {
        FD_CLR(aSock, &_errorSet);
    }
}

int SocketLib::SocketSet::poll(long aTime)
{
    struct timeval t = { 0, aTime};

    m_readSetResult = _readSet;
    m_writeSetResult = _writeSet;
    m_errorSet = _errorSet;

    int ret = 0;

#if defined PLATFORM_WINDOWS
    if(m_readSetResult.fd_count != 0 || m_writeSetResult.fd_count != 0 || m_errorSet.fd_count != 0)
    {
        ret = select( 0, &m_readSetResult, &m_writeSetResult, &m_errorSet, &t );
    }
#else
    if(SOCKET_ERROR != m_maxSock)
    {
        ret = select(m_maxSock + 1, &m_readSetResult, &m_writeSetResult, &m_errorSet, &t );
    }
#endif

    if( ret == SOCKET_ERROR )
    {
        ret = (sErrno != S_EINTR) ? -1 : 0;
    }

    return ret;
}

bool SocketLib::SocketSet::isActive(sock aSock, ActiveType    aType)
{
    bool bActive = false;

    do
    {
        if(aType & ReadActive)
        {
            if((bActive = FD_ISSET(aSock, &m_readSetResult)))
            {
                break;
            }
        }

        if(aType & WriteActive)
        {
            if((bActive = FD_ISSET(aSock, &m_writeSetResult)))
            {
                break;
            }
        }

        if(aType & ErrorActive)
        {
            if((bActive = FD_ISSET(aSock, &m_errorSet)))
            {
                break;
            }
        }
    }
    while(0);

    return bActive;
}

fd_set& SocketLib::SocketSet::getReadFDSet()
{
    return m_readSetResult;
}

fd_set& SocketLib::SocketSet::getWriteFDSet()
{
    return m_writeSetResult;
}

#if defined PLATFORM_LINUX

void SocketLib::SocketSet::pushSock(sock ASock)
{
    int oldSize = m_socks->getSize();
    m_socks->at(ASock) = true;
    int newSize = m_socks->getSize();
    if(newSize > oldSize)
    {
        for(int i = oldSize; i < newSize; i++)
        {
            m_socks->at(i) = false;
        }

        m_socks->at(ASock) = true;
    }

    if (ASock > m_maxSock)
    {
        m_maxSock = ASock;
    }
}

void SocketLib::SocketSet::eraseSock(sock ASock)
{
    m_socks->at(ASock) = false;

    if (ASock == m_maxSock)
    {
        m_maxSock = SOCKET_ERROR;
        for (int i = ASock; i >= 0; --i)
        {
            if (m_socks->at(i))
            {
                m_maxSock = i;
                break;
            }
            
        }
    }
}
#endif
